#include "StdAfx.h"
#include "Word.h"
#include <sstream>

CWord::CWord(void)
{
}

CWord::CWord(const CWord* pWord)
{
	if (pWord != NULL)
	{
		m_keyId = pWord->GetKeyId();

		map<char, int> keys = pWord->GetKeys();

		for(map<char, int>::iterator itr = keys.begin();
			itr != keys.end(); itr++)
		{
			m_map.insert(make_pair(itr->first, itr->second));
		}

		list<string> wordLists = pWord->GetWordList();
		for(list<string>::iterator it = wordLists.begin(); 
			it != wordLists.end(); it++)
		{
			m_wordList.push_back( *it );
		}
	}

}

CWord::CWord(const string& word, map<char, int>& keys, const string& keyId)
{
	m_map = keys;
	m_keyId = keyId;

	if (!word.empty())
	{
		AppendWord(word);
	}
}

CWord::~CWord(void)
{
	m_map.clear();
	m_wordList.clear();
}

const string CWord::GetKeyId() const
{
	return m_keyId;
}

const map<char, int> CWord::GetKeys() const
{
	return m_map;
}

const list<string> CWord::GetWordList() const
{
	return m_wordList;
}

const string CWord::ToString() const
{
	string ret;
	int count = 0;
	int total = m_wordList.size();
	for(list<string>::const_iterator itr = m_wordList.begin();
		 itr != m_wordList.end(); itr++)
	{
		ret.append((*itr));
		if ((++count) < total)
		{
			ret.append(" | ");
		}
	}
	
	return ret;

}

void CWord::AppendWord(const string& word)
{
	m_wordList.push_back(word);
}

//
//calculate KeyIds counter from word
//
map<char, int> CWord::MakeKeys(const string& word)
{
	map<char, int> keyMap;

	for(unsigned int i =0; i<word.length(); ++i)
	{
		char c = word[i];
		if (c >= 'a' && c <= 'z') //filter out some chars
		{
			map<char, int>::iterator itr = keyMap.find(c);
			if (itr != keyMap.end())
			{
				itr->second += 1;
			}
			else
			{
				keyMap.insert(make_pair(c, 1));
			}
		}
	}

	return keyMap;
}

//
// convert map<char,int> to string
//
string CWord::GetKeyId(const map<char, int> & keys)
{
	const int length = 128;
	const int zero = (int)('0');
	int a[length] = {0};
	int index = 0 ;
	for(map<char,int>::const_iterator itr = keys.begin(); 
			itr != keys.end(); itr++)
	{
		int i = (int)itr->first;
		a[i] = itr->second;
		if ( i > index)
		{
			index = i;
		}
	}

	string s;
	for(int i=0; i<= min(index, length); ++i)
	{
		if (a[i] != 0)
		{
			s.push_back((char)i);
			s.push_back((char)( a[i] + zero));
		}
	}
	return s;
}

bool CWord::IsSubSet(const map<char,int>& m)
{
	return CWord::IsSubSet(m_map, m);
}

bool CWord::IsSubSet(const map<char,int>& subM, const map<char, int> & goal)
{
	map<char, int>::const_iterator it1;
	for(it1 = subM.begin(); it1 != subM.end(); it1++)
	{
		map<char, int>::const_iterator it2 = goal.find(it1->first);
		if (it2 == goal.end() || it1->second > it2->second)
		{
			return false;
		}
	}

	return true;
}

bool CWord::IsEqualIfAdd(const map<char,int>& m, const map<char,int>& goal)
{
	map<char, int> ret = Add(m_map, m);
	return IsEqual(ret, goal);
}

map<char, int> CWord::Add(const map<char,int>& m1, const map<char,int>& m2)
{
	map<char, int> ret;
	map<char, int>::const_iterator itr1;
	map<char, int>::const_iterator itr2;

	//merged the same key in m1 & m2
	for(itr1 = m1.begin(); itr1 != m1.end(); itr1++)
	{
		itr2 = m2.find(itr1->first);
		if (itr2 != m2.end())
		{
			ret.insert(make_pair(itr1->first, itr1->second + itr2->second));
		}
		else
		{
			ret.insert(make_pair(itr1->first, itr1->second));
		}

	}

	//search and insert the keys are not in m1
	for(itr2 = m2.begin(); itr2 != m2.end(); itr2++)
	{
		if (m1.find(itr2->first) == m1.end())
		{
			ret.insert(make_pair(itr2->first, itr2->second));
		}
	}

	return ret;
}

bool CWord::IsEqual(const map<char,int>& m1, const map<char,int>& m2)
{
	if (m1.size() == m2.size())
	{
		map<char, int>::const_iterator it1;
		for(it1 = m1.begin(); it1 != m1.end(); it1++)
		{
			map<char, int>::const_iterator it2 = m2.find(it1->first);
			if (it2 == m2.end() || it1->second != it2->second)
			{
				return false;
			}
		}

		return true;
	}
	return false;
}

void CWord::MergeWords(const list<string> & list1, const list<string> & list2)
{
	for(list<string>::const_iterator itr1 = list1.begin();
			itr1 != list1.end(); itr1++)
		{
			for(list<string>::const_iterator itr2 = list2.begin();
				itr2 != list2.end(); itr2++)
			{
				string s = *itr1;
				s.append(",");
				s.append(*itr2 );
				m_wordList.push_back(s);
			}
		}
}

size_t CWord::GetMemoryUsage()
{
	size_t total = sizeof(m_keyId);

	total += m_map.size() * (sizeof(int) + sizeof(char));

	for(list<string>::const_iterator itr = m_wordList.begin();
		itr != m_wordList.end(); itr++)
	{
		total += sizeof( itr->length() * sizeof(char) );
	}

	return total;

}